# -*- coding: utf-8 -*-
# @DATE :  2025/8/4 
# @Author: HQ


import pandas as pd
import numpy as np
import json
import ast
import random
from typing import Optional
from datetime import datetime, timedelta
from woman_config import *
# from task_classification_V0 import *
from month_wh_report import *

date_format = '%Y-%m-%d'
def regular_classification(user_id, message_date):
    """
    # 区分用户规律信息
    #user_type :用户类型，’F'不够数据，0代表不规律，1代表规律
    """

    menstrual_predict_date = message_date['问卷金标'].dropna()
    menstrual_predict_date = pd.to_datetime(menstrual_predict_date)
    # 取该用户的金标数据
    menstrual_cycle_length = message_date['月经周期'].dropna()  # 真实新增
    menstrual_cycle_length = menstrual_cycle_length.tolist()
    user_row_index = message_date.loc[message_date['用户id'] == user_id].index[0]
    message_date.loc[user_row_index, 'user_id'] = user_id

    consecutive_month = all(25 < abs(menstrual_predict_date[i + 1] - date).days < 35 for i, date in
                            enumerate(menstrual_predict_date[:-1]))  # 月经在5天误差内

    differences = [y - x for x in menstrual_cycle_length for y in menstrual_cycle_length if x != y]  # 每两个周期之间的误差
    count_less_than_5 = sum(1 for diff in differences if abs(diff) < 5)

    if count_less_than_5 == len(differences) and count_less_than_5 != 0:

        mean_difference = np.mean(differences)
        std_deviation = np.std(differences)
        medium_cld = np.median(differences)

        if mean_difference < 5 and std_deviation < 3 and medium_cld <= 3:
            consecutive_days = True
        else:
            consecutive_days = False
    else:
        consecutive_days = False

    if consecutive_month:
        message_date.loc[user_row_index, '月经全部连续'] = 1
    else:
        message_date.loc[user_row_index, '月经全部连续'] = 0

    if consecutive_days:
        message_date.loc[user_row_index, '月经规律（5日内）'] = 1
        user_type = 1
    else:
        message_date.loc[user_row_index, '月经规律（5日内）'] = 0
        user_type = 0

    return user_type, message_date

def generate_random_values(type_key: str, n: Optional[int] = None) -> list:
    if n is None:
        n = random.randint(1, 10)

    if type_key == 'blood':
        choices = [20, 40, 60, 80, 100, -1]
        return random.choices(choices, k=n)

    elif type_key == 'pain':
        choices = [1, 2, 3, 4, 5, -1]
        return random.choices(choices, k=n)

    elif type_key == 'pain_total':
        return [random.randint(1, 30) for _ in range(n)]

    else:
        raise ValueError(f"不支持的类型: {type_key}")

def random_with_neg1(start: int, end: int) -> int:
    """在 [start, end] 和 -1 中随机选一个值"""
    return random.choice(list(range(start, end + 1)) + [-1])

def generate_user_symptom_records() -> list:
    n = random.randint(2, 5)
    # 从 1~7 中取 n 个不重复的 symptom 值
    symptom_choices = random.sample(range(1, 8), k=n)

    records = []
    for symptom in symptom_choices:
        record = {
            'symptom': symptom,
            'mens': random_with_neg1(1, 5),
            'folli': random_with_neg1(1, 6),
            'ovula': random_with_neg1(1, 7),
            'lm': random_with_neg1(1, 10),
        }
        records.append(record)
    return records

def generate_unique_mood_records_desc(mens_start_date: datetime, mens_end_date: datetime, max_len: int = 180) -> list:
    days_range = (mens_end_date - mens_start_date).days + 1
    max_records = min(days_range, max_len)  # 最多不能超过日期范围天数

    record_len = random.randint(0, max_records)  # 随机生成长度，最多max_records

    all_dates = [mens_start_date + timedelta(days=i) for i in range(days_range)]

    selected_dates = random.sample(all_dates, k=record_len)

    mood_records = []
    for d in selected_dates:
        mood = random.randint(1, 5)
        mood_records.append({
            'date_sleep': d.strftime('%Y-%m-%d'),
            'mood': mood
        })

    # 按日期倒序排序
    mood_records.sort(key=lambda x: x['date_sleep'], reverse=True)

    return mood_records


def default_to_native(obj):
    if isinstance(obj, (np.integer, np.int32, np.int64)):
        return int(obj)
    elif isinstance(obj, (np.floating, np.float32, np.float64)):
        return float(obj)
    else:
        raise TypeError(f"{type(obj)} is not JSON serializable")


def gen_csv(mens_report):
    df_all = pd.DataFrame()
    mens_report.loc[i, 'user_id'] = id
    mens_report.loc[i, 'cycles_len'] = len(cycles_input['mens_cycle_len_6'])
    mens_report.loc[i, 'input'] = str(cycles_input)
    mens_report.loc[i, 'output'] = str(cycles_output)
    for idx, text in enumerate(texts_cycle, start=1):  # 从1开始计数，对应text1、text2...
        col_name = f"text{idx}"  # 生成列名：text1、text2、text3...
        mens_report.loc[i, col_name] = text
    # print('输出', output)
    mens_dates_csv = pd.concat([mens_dates_csv, mens_report])

# graph = CommunityGraph()
# for config in template_configs:
#     node = TemplateNode(**config)
#     graph.add_node(node)
#
#
# def gen_menstrual_cycles_monthly_report(cycles_input):
#     cycle_output = {
#         'user_id': cycles_input['user_id'],
#         'error':{'error_type': 0, 'error_content': None, 'error_date': None}
#     }
#     matched_templates = graph.match_templates(cycles_input)
#     cycle_templates = [t for t in matched_templates if t.community == '周期统计']
#     # print('周期内容', cycle_templates, matched_templates)
#     texts_info = []
#     for t in cycle_templates:
#         group = t.group
#         # print('这些组', group)
#         output_key = group_to_output_key.get(group)
#
#         if output_key:
#             template_key = document_key.get(t.id)
#             text_info, key_values , _ = t.render(cycles_input)
#             texts_info.append(text_info)
#             template_info = {'key': template_key,
#                              'value': key_values}
#             cycle_output[output_key] = template_info
#
#     return cycle_output
#
#
# def gen_temperature_monthly_reports(temp_input):
#     temp_data = temp_input['temp_data']
#     temp_data = pd.DataFrame(temp_data, columns=['date_sleep', 'temp_benchmark', 'temp_offset', 'flag'])
#     temp_data.iloc[:, 1:] = temp_data.iloc[:, 1:].astype(float)
#     temp_data['temp'] = temp_data['temp_benchmark'] + temp_data['temp_offset']
#     temp_data['date_sleep'] = pd.to_datetime(temp_data['date_sleep'])
#     temp_data['error'] = 0
#     data_list, del_user = data_predo(temp_data, 'temp')
#     data_frame = pd.DataFrame(data_list)
#     data_frame['date_sleep'] = pd.to_datetime(data_frame['date_sleep'])
#     data_1 = data_filter(data_frame['temp'], 3, 3, 0.08)
#     data_2 = data_filter(data_frame['temp'], 3, 7, 0.6)
#     data_new = np.array(data_2) - np.array(data_1)
#     temp_fil = data_new + np.mean(data_frame['temp'])
#     data_frame['filter'] = temp_fil
#     data_frame['filter'] = data_frame['filter'].round(2)
#     mens_dates = temp_input['menstrual_dates']
#     sorted_dates = sorted(
#         mens_dates,
#         key=lambda x: datetime.strptime(x['mens_date'], '%Y-%m-%d'),
#         reverse=True
#     )
#
#     temp_anlzr = []
#     for i in range(len(sorted_dates) - 1):
#         temp_anlzr_i = {}
#         end_date = pd.to_datetime(sorted_dates[i]['mens_date'])
#         start_date = pd.to_datetime(sorted_dates[i + 1]['mens_date'])
#
#         temp_data = data_frame[(data_frame['date_sleep'] >= start_date) & (data_frame['date_sleep'] < end_date)].copy()
#         cycle_all_days = (end_date - start_date).days
#         wear_temp_days = len(temp_data[temp_data['error'] == 0])
#         wear_date_ratio = round(wear_temp_days / cycle_all_days, 2)
#         temp_data['date_sleep'] = temp_data['date_sleep'].dt.strftime("%Y-%m-%d")
#         temp_input_i = {'temp_data': temp_data[['date_sleep', 'filter']],
#                       'start_date': start_date,
#                       'end_date': end_date,
#                       'wear_temp_days': cycle_all_days,
#                       'wear_date_ratio': wear_date_ratio
#                       }
#
#         matched_templates = graph.match_templates(temp_input_i)
#         cycle_templates = [t for t in matched_templates if t.community == '皮肤温度']
#
#         for t in cycle_templates:
#             group_id = t.group
#             output_key = group_to_output_key.get(group_id)
#
#             if output_key:
#                 template_key = document_key.get(t.id)
#                 text_info, key_values, params_value = t.render(temp_input_i)
#                 start_date_str = start_date.strftime('%Y-%m-%d')
#
#                 temp_anlzr_i['start_date'] = start_date_str
#                 temp_anlzr_i['period_len'] = next(
#                     (d['period_len'] for d in sorted_dates if d['mens_date'] == start_date), 5)
#                 temp_anlzr_i['low_temp'] = params_value['low_temp']
#                 temp_anlzr_i['high_temp'] = params_value['high_temp']
#                 temp_anlzr_i['delta_temp'] = params_value['delta_temp']
#                 temp_anlzr_i['temp_data_filter'] = params_value['real_filter_temp']
#                 temp_anlzr_i['anlzr'] = {'key': template_key,
#                                          'value': key_values}
#                 temp_anlzr.append(temp_anlzr_i)
#
#     cycle_output = {
#         'user_id': temp_input['user_id'],
#         'temp_anlzr': temp_anlzr,
#         'error': {'error_type': 0, 'error_content': None, 'error_date': None}
#
#     }
#
#     return cycle_output
#
#
# def gen_pain_symptoms_monthly_report(pain_symptom_input):
#     pain_symptom_output = {
#         'user_id': pain_symptom_input['user_id'],
#         'error': {'error_type': 0, 'error_content': None, 'error_date': None}
#     }
#     matched_templates = graph.match_templates(pain_symptom_input)
#     cycle_templates = [t for t in matched_templates if t.community == '痛经与症状']
#
#     texts_info = []
#     for t in cycle_templates:
#         group = t.group
#
#         output_key = group_to_output_key.get(group)
#
#         if output_key:
#             template_key = document_key.get(t.id)
#             text_info, key_values, _ = t.render(pain_symptom_input)
#             texts_info.append(text_info)
#             template_info = {'key': template_key,
#                              'value': key_values}
#             pain_symptom_output[output_key] = template_info
#
#
#     return pain_symptom_output
#
#
# def gen_hrv_mood_monthly_reports(hrv_input):
#     hrv_data = hrv_input['hrv_data']
#     hrv_data_df = pd.DataFrame(hrv_data, columns=['date_sleep', 'hr_avg', 'hrv_avg', 'flag'])
#     hrv_data_df.iloc[:, 1:] = hrv_data_df.iloc[:, 1:].astype(float)
#     hrv_data_df['date_sleep'] = pd.to_datetime(hrv_data_df['date_sleep'])
#
#     mood_records = hrv_input['mood_records']
#     mood_records = pd.DataFrame(mood_records)
#     mood_records['date_sleep'] = pd.to_datetime(mood_records['date_sleep'])
#
#     mens_dates = hrv_input['menstrual_dates']
#     mens_cycles, error = create_every_cycles(mens_dates)
#     sorted_dates = sorted(
#         mens_dates,
#         key=lambda x: datetime.strptime(x['mens_date'], '%Y-%m-%d'),
#         reverse=True
#     )
#
#     hrv_anlzr = []
#     for i in range(len(sorted_dates) - 1):
#         hrv_anlzr_i = {}
#         end_date = pd.to_datetime(sorted_dates[i]['mens_date'])
#         start_date = pd.to_datetime(sorted_dates[i + 1]['mens_date'])
#         hr_data_i = hrv_data_df[(hrv_data_df['date_sleep'] >= start_date) & (hrv_data_df['date_sleep'] < end_date)].copy()
#         mood_records_i = mood_records[(mood_records['date_sleep'] >= start_date) & (mood_records['date_sleep'] < end_date)].copy()
#
#         cycle_all_days = (end_date - start_date).days
#         wear_temp_days = len(hr_data_i)
#         wear_date_ratio = round(wear_temp_days / cycle_all_days, 2)
#         # print( 'mens_cycles', mens_cycles)
#         hrv_mood_input = {'hrv_data': hr_data_i,
#                           'mens_cycle': mens_cycles[i],
#                           'mood_records': mood_records_i,
#                           'wear_data_ratio': wear_date_ratio
#                           }
#         hrv_mood_info = cal_hrv_params(hrv_mood_input)
#         matched_templates = graph.match_templates(hrv_mood_info)
#
#         cycle_templates = [t for t in matched_templates if t.community == 'HRV与心情']
#         for t in cycle_templates:
#             group_id = t.group
#             output_key = group_to_output_key.get(group_id)
#             if output_key:
#                 template_key = document_key.get(t.id)
#                 text_info, key_values, params_value = t.render(hrv_mood_info)
#                 start_date_str = start_date.strftime('%Y-%m-%d')
#                 hrv_anlzr_i['start_date'] = start_date_str
#                 hrv_anlzr_i['period_len'] = next((d['period_len'] for d in sorted_dates if d['mens_date'] == start_date), 5)
#                 hrv_anlzr_i['anlzr'] = {'key': template_key,
#                                         'value': key_values}
#                 hrv_anlzr.append(hrv_anlzr_i)
#
#     hrv_output = {
#         'user_id': hrv_input['user_id'],
#         'hrv_anlzr': hrv_anlzr,
#         'error': {'error_type': 0, 'error_content': None, 'error_date': None}
#
#     }
#     return hrv_output
#
#
# def cal_hrv_params(user_data):
#     pos_desc = None
#     neg_desc = None
#     hrv_data = user_data.get("hrv_data")
#     menstrual_cycle = user_data.get("mens_cycle")
#     mood_records = user_data.get("mood_records", [])
#     wear_date_ratio = user_data.get("wear_date_ratio", 0)
#     # mood_df = pd.DataFrame(mood_records)
#     # hrv_data['date_sleep'] = pd.to_datetime(hrv_data['date_sleep'])
#     # mood_df['date_sleep'] = pd.to_datetime(mood_df['date_sleep'])
#     merged = pd.merge(hrv_data, mood_records, how='inner', on='date_sleep')
#
#
#     hrv_tag = cal_hrv_tag(hrv_data, menstrual_cycle)
#     hrv_diff_value = hrv_tag['hrv_pattern']
#     hrv_trend = "符合" if hrv_diff_value > 0 else "不符"
#     hrv_diff = "高于" if hrv_diff_value > 0 else "低于"
#
#     if len(mood_records) <= 0 :
#         hrv_mood_key = 'no mood record'
#     else:
#         if wear_date_ratio < 0.5:
#             hrv_mood_key = 'hrv data ≤50%'
#         else:
#
#             pos_hrv_mood = merged[(merged['mood'] == 1) & (merged['mood'] == 2)]['hrv_avg']
#             neg_hrv_mood = merged[(merged['mood'] == 3) & (merged['mood'] == 4) & (merged['mood'] == 5)]['hrv_avg']
#             pos_mean = pos_hrv_mood.mean()
#             neg_mean = neg_hrv_mood.mean()
#             diff_ratio = abs(pos_mean - neg_mean) / max(pos_mean, neg_mean)
#
#             if diff_ratio < 0.05:
#                 hrv_mood_key = 'hrv and mood unrelated'
#             else:
#                 pos_desc = "高" if pos_mean > neg_mean else "低"
#                 neg_desc = "高" if neg_mean > pos_mean else "低"
#                 hrv_mood_key = 'hrv and mood related'
#     hrv_params = {'hrv_diff': hrv_diff,
#             'hrv_trend': hrv_trend,
#             'pos_des': pos_desc,
#             'neg_des': neg_desc,
#             'hrv_mood_key':hrv_mood_key
#
#             }
#     # print('计算的hrv参数', hrv_params)
#     return hrv_params
# def cal_hrv_tag(data, mens_cycle):
#     """计算hrv标签"""
#     hrv_tag = {}
#
#     mens_date = change_time(mens_cycle, 'mens_pred_date')
#     ovula_date = change_time(mens_cycle, 'ovul_pred_date')
#     mens_date_next = change_time(mens_cycle, 'mens_next_date')
#
#     folli_hrv_data = data[(data['date_sleep'] >= mens_date) & (data['date_sleep'] < ovula_date)]
#     lm_hrv_data = data[(data['date_sleep'] > ovula_date) & (data['date_sleep'] < mens_date_next)]
#     hrv_data = data[(data['date_sleep']>= mens_date) & (data['date_sleep'] < mens_date_next)]
#
#     folli_hrv_avg = np.mean(folli_hrv_data['hrv_avg'])
#     lm_hrv_avg = np.mean(lm_hrv_data['hrv_avg'])
#     hrv_avg = np.mean(hrv_data['hrv_avg'])
#
#     hrv_diff = folli_hrv_avg - lm_hrv_avg
#
#     hrv_tag['hrv_pattern'] = hrv_diff
#     hrv_tag['hrv_avg'] = hrv_avg
#
#     return hrv_tag

def analyze_menstrual_cycle_hrv_mood(hrv_data, menstrual_dates, mood_data):
    """
    分析用户在不同月经周期阶段的HRV和情绪数据
    
    参数:
    hrv_data: list, 格式为 [['2024-05-24', '60.0', '64.0', '1'], ['2024-05-25', '56.0', '77.0', '1']]
              每个子列表包含 [日期, 心率均值, HRV均值, 标志位]
    menstrual_dates: list, 格式为 [{'mens_date': '2025-06-04', 'period_len': 5}, ...]
    mood_data: list, 格式为 [{'date_sleep': '2024-07-27', 'mood': 3}, ...]
               mood值: 1-2为正面情绪, 3-5为负面情绪
    
    返回:
    dict: 包含四个阶段的分析结果
    """
    
    # 转换数据格式
    hrv_df = pd.DataFrame(hrv_data, columns=['date_sleep', 'hr_avg', 'hrv_avg', 'flag'])
    hrv_df['date_sleep'] = pd.to_datetime(hrv_df['date_sleep'])
    hrv_df['hrv_avg'] = hrv_df['hrv_avg'].astype(float)
    hrv_df['hr_avg'] = hrv_df['hr_avg'].astype(float)
    
    mood_df = pd.DataFrame(mood_data)
    mood_df['date_sleep'] = pd.to_datetime(mood_df['date_sleep'])
    
    # 按日期排序月经数据
    sorted_mens_dates = sorted(menstrual_dates, 
                              key=lambda x: datetime.strptime(x['mens_date'], '%Y-%m-%d'), 
                              reverse=True)
    
    results = {}
    
    # 分析每个周期
    for i in range(len(sorted_mens_dates) - 1):
        current_mens = pd.to_datetime(sorted_mens_dates[i]['mens_date'])
        next_mens = pd.to_datetime(sorted_mens_dates[i + 1]['mens_date'])
        period_len = sorted_mens_dates[i + 1]['period_len']
        
        # 计算周期长度
        cycle_length = (current_mens - next_mens).days
        
        # 定义四个阶段
        # 月经期: 月经开始日 到 月经开始日+经期天数
        mens_start = next_mens
        mens_end = mens_start + timedelta(days=period_len)
        
        # 卵泡期: 月经结束日 到 排卵日前
        folli_start = mens_end
        ovulation_day = mens_start + timedelta(days=cycle_length // 2)  # 简化计算，实际排卵日约在周期中点
        folli_end = ovulation_day
        
        # 排卵期: 排卵日前后各2天
        ovula_start = ovulation_day - timedelta(days=2)
        ovula_end = ovulation_day + timedelta(days=2)
        
        # 黄体期: 排卵期结束 到 下次月经开始
        lm_start = ovula_end
        lm_end = current_mens
        
        phases = {
            'menstrual': (mens_start, mens_end, '月经期'),
            'follicular': (folli_start, folli_end, '卵泡期'), 
            'ovulatory': (ovula_start, ovula_end, '排卵期'),
            'luteal': (lm_start, lm_end, '黄体期')
        }
        
        cycle_result = {}
        
        for phase_name, (start_date, end_date, phase_desc) in phases.items():
            # 获取该阶段的HRV数据
            phase_hrv = hrv_df[(hrv_df['date_sleep'] >= start_date) & 
                              (hrv_df['date_sleep'] < end_date)].copy()
            
            # 获取该阶段的情绪数据
            phase_mood = mood_df[(mood_df['date_sleep'] >= start_date) & 
                                (mood_df['date_sleep'] < end_date)].copy()
            
            # 计算阶段天数
            N = (end_date - start_date).days
            if N <= 0:
                continue
                
            # 分析该阶段
            phase_analysis = analyze_phase_data(phase_hrv, phase_mood, N, hrv_df)
            phase_analysis['phase_name'] = phase_desc
            phase_analysis['start_date'] = start_date.strftime('%Y-%m-%d')
            phase_analysis['end_date'] = end_date.strftime('%Y-%m-%d')
            phase_analysis['total_days'] = N
            
            cycle_result[phase_name] = phase_analysis
        
        cycle_key = f"cycle_{i+1}_{next_mens.strftime('%Y-%m-%d')}"
        results[cycle_key] = cycle_result
    
    return results


def analyze_phase_data(phase_hrv, phase_mood, N, all_hrv_data):
    """
    分析单个阶段的HRV和情绪数据
    """
    # 计算HRV基线（使用所有HRV数据的均值）
    hrv_baseline = all_hrv_data['hrv_avg'].mean()
    
    # 计算各种阈值
    T_07 = round(0.7 * N)  # 四舍五入
    T_04 = round(0.4 * N)
    T_014 = round(0.14 * N)
    T_05 = round(0.5 * N)
    F_03 = round(0.3 * N)
    
    # 初始化计数器
    hrv_good_days = 0  # HRV在基线±20%内的天数
    hrv_bad_days = 0   # HRV低于基线20%以上的天数
    big_fluctuation_days = 0  # 大幅波动天数
    negative_mood_days = 0  # 负面情绪天数
    missing_hrv_days = N - len(phase_hrv)  # 缺失HRV数据天数
    
    # 分析HRV数据
    if len(phase_hrv) > 0:
        phase_hrv = phase_hrv.sort_values('date_sleep')
        
        for idx, row in phase_hrv.iterrows():
            hrv_value = row['hrv_avg']
            
            # 判断HRV是否在基线±20%内
            if abs(hrv_value - hrv_baseline) / hrv_baseline <= 0.2:
                hrv_good_days += 1
            elif hrv_value < hrv_baseline * 0.8:  # 低于基线20%以上
                hrv_bad_days += 1
            
            # 计算相对前一天的波动幅度
            if idx > 0:
                prev_hrv = phase_hrv.iloc[idx-1]['hrv_avg'] if idx > 0 else hrv_value
                if prev_hrv > 0:
                    fluctuation = abs(hrv_value - prev_hrv) / prev_hrv
                    if fluctuation >= 0.2:  # 波动幅度≥20%
                        big_fluctuation_days += 1
    
    # 分析情绪数据
    for _, mood_row in phase_mood.iterrows():
        if mood_row['mood'] in [3, 4, 5]:  # 负面情绪
            negative_mood_days += 1
    
    # 根据规则判断等级
    rating = determine_rating(
        hrv_good_days, hrv_bad_days, big_fluctuation_days, 
        negative_mood_days, missing_hrv_days,
        T_07, T_04, T_014, T_05, F_03
    )
    
    return {
        'rating': rating,
        'hrv_baseline': round(hrv_baseline, 2),
        'hrv_good_days': hrv_good_days,
        'hrv_bad_days': hrv_bad_days,
        'big_fluctuation_days': big_fluctuation_days,
        'negative_mood_days': negative_mood_days,
        'missing_hrv_days': missing_hrv_days,
        'thresholds': {
            'T_07': T_07,
            'T_04': T_04, 
            'T_014': T_014,
            'T_05': T_05,
            'F_03': F_03
        },
        'hrv_data_count': len(phase_hrv),
        'mood_data_count': len(phase_mood)
    }


def determine_rating(hrv_good_days, hrv_bad_days, big_fluctuation_days, 
                    negative_mood_days, missing_hrv_days,
                    T_07, T_04, T_014, T_05, F_03):
    """
    根据规则确定评级
    """
    # 数据不足：存在≥T(0.5*N)天缺少睡眠HRV数据
    if missing_hrv_days >= T_05:
        return "数据不足"
    
    # 优秀条件
    if (hrv_good_days > T_07 and 
        big_fluctuation_days < T_014 and 
        negative_mood_days < F_03):
        return "优秀"
    
    # 良好条件  
    if (hrv_good_days > T_07 and 
        big_fluctuation_days < T_014 and 
        negative_mood_days > F_03):
        return "良好"
    
    # 一般条件
    condition_1 = hrv_bad_days > T_04
    condition_2 = big_fluctuation_days >= T_014
    
    if ((condition_1 or condition_2) and negative_mood_days <= F_03):
        return "一般"
    
    # 较差条件
    if ((condition_1 or condition_2) and negative_mood_days > F_03):
        return "较差"
    
    # 默认返回一般
    return "一般"


def calculate_key_change_points(menstrual_data):
    """
    计算女性生理周期的关键变化点
    
    参数:
    menstrual_data: list of dict, 格式为 [{'date': '2025-07-01', 'structural_status': 2}, ...]
                   其中 structural_status: 2=体温正常, 1=节律不明, 0=数据不足
                   date: 月经周期第一天的日期
    
    返回:
    list: 最新的3个关键变化点，格式为:
          [{'date': '2025-07-01', 'key': '首次异常', 'value': []}, ...]
    """
    if not menstrual_data or len(menstrual_data) < 2:
        return []
    
    # 按日期排序，最新的在前
    sorted_data = sorted(menstrual_data, 
                        key=lambda x: datetime.strptime(x['date'], '%Y-%m-%d'), 
                        reverse=True)
    
    # 提取状态序列和对应日期
    statuses = [item['structural_status'] for item in sorted_data]
    dates = [item['date'] for item in sorted_data]
    
    key_changes = []
    
    # 从最新到最老分析序列
    for i in range(len(statuses)):
        current_status = statuses[i]
        current_date = dates[i]
        
        # 首次异常：从正常(2)变为异常(1)
        if (current_status == 1 and 
            i < len(statuses) - 1 and 
            statuses[i + 1] == 2):
            key_changes.append({
                'date': current_date,
                'key': '首次异常',
                'value': []
            })
        
        # 首次恢复：从异常(1)变为正常(2)
        if (current_status == 2 and 
            i < len(statuses) - 1 and 
            statuses[i + 1] == 1):
            key_changes.append({
                'date': current_date,
                'key': '首次恢复',
                'value': []
            })
    
    # 查找连续异常的最新点
    i = 0
    while i < len(statuses):
        if statuses[i] == 1:  # 发现异常点
            # 找到连续异常区间的开始
            consecutive_start = i
            consecutive_end = i
            
            # 向前查找连续异常的结束位置
            while consecutive_end < len(statuses) - 1 and statuses[consecutive_end + 1] == 1:
                consecutive_end += 1
            
            # 如果连续异常长度 >= 2，标记最新的点（索引最小的点）
            if consecutive_end - consecutive_start >= 1:
                key_changes.append({
                    'date': dates[consecutive_start],
                    'key': '连续异常',
                    'value': []
                })
            
            # 跳过已处理的连续区间
            i = consecutive_end + 1
        else:
            i += 1
    
    # 按日期排序，最新的在前，并取最新的3个
    key_changes.sort(key=lambda x: datetime.strptime(x['date'], '%Y-%m-%d'), reverse=True)
    
    return key_changes[:3]


def test_key_change_points():
    """
    测试关键变化点计算函数
    """
    print("=== 测试关键变化点计算函数 ===")
    
    # 测试用例1：您提到的例子 [1,1,1,0,2]
    test_data_1 = [
        {'date': '2025-01-01', 'structural_status': 2},  # 最新
        {'date': '2024-12-01', 'structural_status': 0},  
        {'date': '2024-11-01', 'structural_status': 1},  # 连续异常最新点
        {'date': '2024-10-01', 'structural_status': 1},  
        {'date': '2024-09-01', 'structural_status': 1},  # 首次异常
    ]
    
    print("\n测试用例1: [2,0,1,1,1] (从新到老)")
    result_1 = calculate_key_change_points(test_data_1)
    for item in result_1:
        print(f"  日期: {item['date']}, 变化点: {item['key']}")
    
    # 测试用例2：包含多个分离的异常区间
    test_data_2 = [
        {'date': '2025-01-01', 'structural_status': 2},  # 首次恢复
        {'date': '2024-12-01', 'structural_status': 1},  # 连续异常最新点
        {'date': '2024-11-01', 'structural_status': 1},  
        {'date': '2024-10-01', 'structural_status': 0},  
        {'date': '2024-09-01', 'structural_status': 2},  # 首次恢复
        {'date': '2024-08-01', 'structural_status': 1},  # 连续异常最新点
        {'date': '2024-07-01', 'structural_status': 1},  
        {'date': '2024-06-01', 'structural_status': 2},  
    ]
    
    print("\n测试用例2: 多个异常区间")
    result_2 = calculate_key_change_points(test_data_2)
    for item in result_2:
        print(f"  日期: {item['date']}, 变化点: {item['key']}")
    
    # 测试用例3：只有单个异常点
    test_data_3 = [
        {'date': '2025-01-01', 'structural_status': 2},
        {'date': '2024-12-01', 'structural_status': 1},  # 首次异常
        {'date': '2024-11-01', 'structural_status': 2},
    ]
    
    print("\n测试用例3: 单个异常点")
    result_3 = calculate_key_change_points(test_data_3)
    for item in result_3:
        print(f"  日期: {item['date']}, 变化点: {item['key']}")
    
    print("\n=== 测试完成 ===")


if __name__ == '__main__':
    import pprint
    import task_classification

    """
    pd.set_option("display.max_rows", None)  # 显示所有行
    pd.set_option("display.max_columns", None)  # 显示所有列
    pd.set_option("display.width", None)  # 不限制每行的宽度
    pd.set_option("display.max_colwidth", None)  # 每列最大宽度（None = 不限制）
    
    # 测试关键变化点函数
    # test_key_change_points()
    
    # # 测试数据
    # hrv_test_data = [
    #     ['2024-05-24', '60.0', '64.0', '1'],
    #     ['2024-05-25', '56.0', '77.0', '1'],
    #     ['2024-05-26', '58.0', '65.0', '1'],
    #     ['2024-05-27', '62.0', '70.0', '1'],
    #     ['2024-06-01', '59.0', '68.0', '1'],
    #     ['2024-06-02', '61.0', '72.0', '1'],
    #     ['2024-06-15', '57.0', '66.0', '1'],
    #     ['2024-06-16', '63.0', '74.0', '1']
    # ]
    #
    # menstrual_test_data = [
    #     {'mens_date': '2025-06-04', 'period_len': 5},
    #     {'mens_date': '2025-05-11', 'period_len': 3},
    #     {'mens_date': '2025-04-11', 'period_len': 2}
    # ]
    #
    # mood_test_data = [
    #     {'date_sleep': '2024-05-24', 'mood': 3},
    #     {'date_sleep': '2024-05-25', 'mood': 2},
    #     {'date_sleep': '2024-05-26', 'mood': 4},
    #     {'date_sleep': '2024-06-01', 'mood': 1},
    #     {'date_sleep': '2024-06-02', 'mood': 3}
    # ]
    #
    # # 测试函数
    # result = analyze_menstrual_cycle_hrv_mood(hrv_test_data, menstrual_test_data, mood_test_data)
    # print("月经周期HRV情绪分析结果:")
    # pprint.pprint(result, width=100)

    # input_cycle ={'user_id': 44575, 'user_age': 9, 'mens_cycle_len_6': [9, 9, 9, 9, 9, 3, 4, 67, 32, 56], 'mens_period_len_6': [11, 12, 11, 11, 11, 17, 18, 20, 87, 56], 'mens_blood_len_6': [-1, -1, -1, -1, -1, -1, -1, -1, -1]}
    # output_cycle = gen_menstrual_cycles_monthly_report(input_cycle)
    # print(input_cycle)
    # print(output_cycle)
    # # # # # pprint.pprint(output_cycle, width=80, compact=True)
    # # #
    # input_pain ={'user_id': 31317, 'user_pain_records': [4, 5, -1, -1, 5, -1, 2, 2], 'user_pain_total_cycles': [5, 11, 2], 'user_symptom_records': [{'symptom': 7, 'mens': -1, 'folli': -1, 'ovula': 1, 'lm': -1}, {'symptom': 2, 'mens': 1, 'folli': -1, 'ovula': -1, 'lm': -1}]}
    # output_cycle = gen_pain_symptoms_monthly_report(input_pain)
    # print('症状',output_cycle)
    #
    hrv_input ={'user_id': 45840, 'hrv_data': [['2025-06-02', '79', '31', '1'], ['2025-06-03', '79', '29', '1'], ['2025-06-04', '79', '29', '1'], ['2025-06-05', '73', '32', '1'], ['2025-06-06', '76', '42', '1'], ['2025-06-07', '81', '28', '1'], ['2025-06-08', '81', '23', '1'], ['2025-06-09', '72', '33', '1'], ['2025-06-11', '74', '34', '1'], ['2025-06-12', '79', '26', '1'], ['2025-06-13', '71', '39', '1'], ['2025-06-14', '80', '23', '1'], ['2025-06-15', '80', '28', '1'], ['2025-06-16', '77', '23', '1'], ['2025-06-17', '74', '30', '1'], ['2025-06-18', '73', '32', '1'], ['2025-06-19', '77', '25', '1'], ['2025-06-20', '74', '30', '1'], ['2025-06-21', '83', '21', '1'], ['2025-06-22', '77', '35', '1'], ['2025-06-23', '80', '26', '1'], ['2025-06-24', '77', '27', '1'], ['2025-06-25', '73', '31', '1'], ['2025-06-26', '77', '31', '1'], ['2025-06-27', '74', '31', '1'], ['2025-06-28', '73', '30', '1'], ['2025-06-29', '72', '43', '1'], ['2025-06-30', '79', '34', '1'], ['2025-07-01', '73', '29', '1'], ['2025-07-02', '73', '35', '1'], ['2025-07-03', '72', '33', '1'], ['2025-07-04', '70', '31', '1'], ['2025-07-05', '69', '38', '1'], ['2025-07-06', '70', '41', '1'], ['2025-07-07', '76', '28', '1'], ['2025-07-08', '79', '23', '1'], ['2025-07-09', '75', '27', '1'], ['2025-07-10', '73', '29', '1'], ['2025-07-11', '79', '23', '1'], ['2025-07-12', '87', '24', '1'], ['2025-07-13', '83', '27', '1'], ['2025-07-14', '72', '35', '1'], ['2025-07-15', '83', '21', '1'], ['2025-07-16', '76', '25', '1'], ['2025-07-17', '77', '25', '1'], ['2025-07-18', '74', '35', '1'], ['2025-07-22', '76', '27', '1'], ['2025-07-23', '84', '34', '1'], ['2025-07-24', '76', '49', '1'], ['2025-07-25', '77', '41', '1'], ['2025-07-26', '71', '36', '1'], ['2025-07-27', '74', '40', '1'], ['2025-07-28', '81', '33', '1'], ['2025-07-29', '77', '57', '1'], ['2025-07-30', '74', '45', '1'], ['2025-07-31', '74', '42', '1'], ['2025-08-01', '72', '33', '1'], ['2025-08-02', '76', '31', '1'], ['2025-08-03', '76', '35', '1'], ['2025-08-04', '70', '34', '1'], ['2025-08-05', '73', '27', '1'], ['2025-08-06', '74', '29', '1'], ['2025-08-07', '75', '27', '1'], ['2025-08-09', '76', '28', '1'], ['2025-08-10', '82', '26', '1'], ['2025-08-11', '79', '26', '1'], ['2025-08-12', '84', '22', '1'], ['2025-08-13', '81', '25', '1'], ['2025-08-14', '78', '33', '1'], ['2025-08-15', '74', '33', '1'], ['2025-08-16', '74', '34', '1'], ['2025-08-17', '77', '25', '1'], ['2025-08-18', '81', '23', '1'], ['2025-08-19', '76', '26', '1'], ['2025-08-20', '77', '28', '1'], ['2025-08-21', '83', '26', '1'], ['2025-08-22', '76', '28', '1'], ['2025-08-23', '82', '25', '1'], ['2025-08-24', '82', '32', '1'], ['2025-08-25', '81', '28', '1'], ['2025-08-26', '79', '34', '1'], ['2025-08-27', '77', '28', '1'], ['2025-08-28', '76', '32', '1'], ['2025-08-29', '73', '30', '1']], 'menstrual_dates': [{'mens_date': '2025-09-24', 'period_len': 6}, {'mens_date': '2025-08-26', 'period_len': 4}, {'mens_date': '2025-08-05', 'period_len': 7}, {'mens_date': '2025-07-15', 'period_len': 3}, {'mens_date': '2025-07-04', 'period_len': 3}, {'mens_date': '2025-06-15', 'period_len': 10}, {'mens_date': '2025-06-04', 'period_len': 10}], 'mood_records': []}
    hrv_outpt = gen_hrv_mood_monthly_reports(hrv_input)
    print('hrv输入',hrv_input)
    print('hrv输出',hrv_outpt)
    #
    # #
    #
    temp_input ={'user_id': 32391, 'temp_data': [['2025-01-20', '36.34', '-0.09', '1'], ['2025-01-23', '36.32', '-0.22', '1'], ['2025-01-27', '36.29', '-0.23', '1'], ['2025-02-02', '36.24', '0.21', '1'], ['2025-02-05', '36.22', '0.36', '1'], ['2025-03-19', '36.22', '0.36', '1'], ['2025-03-20', '36.22', '0.36', '1'], ['2025-03-21', '36.22', '0.36', '1'], ['2025-03-22', '36.22', '0.36', '1'], ['2025-03-23', '36.22', '0.36', '1'], ['2025-03-24', '36.22', '0.36', '1'], ['2025-03-25', '36.22', '0.36', '1'], ['2025-03-26', '35.70', '0.00', '1'], ['2025-03-27', '35.70', '0.06', '1'], ['2025-03-28', '35.73', '0.35', '1'], ['2025-03-29', '35.85', '-0.11', '1'], ['2025-03-30', '35.82', '-0.35', '1'], ['2025-03-31', '35.75', '-0.30', '1'], ['2025-04-01', '35.70', '0.44', '1'], ['2025-04-04', '35.76', '-0.32', '1'], ['2025-04-05', '35.72', '-0.23', '1'], ['2025-04-06', '35.70', '-0.32', '1'], ['2025-04-07', '35.66', '-0.01', '1'], ['2025-04-08', '35.66', '0.07', '1'], ['2025-04-09', '35.67', '-0.03', '1'], ['2025-04-10', '35.67', '0.04', '1'], ['2025-04-11', '35.67', '0.14', '1'], ['2025-04-12', '35.68', '0.17', '1'], ['2025-04-13', '35.69', '0.20', '1'], ['2025-04-14', '35.70', '-0.21', '1'], ['2025-04-15', '35.69', '0.02', '1'], ['2025-04-16', '35.69', '-0.05', '1'], ['2025-04-17', '35.69', '0.01', '1'], ['2025-04-18', '35.69', '-0.11', '2'], ['2025-04-20', '35.68', '0.10', '1'], ['2025-04-21', '35.69', '0.54', '1'], ['2025-04-29', '35.69', '-0.25', '1'], ['2025-04-30', '35.68', '-0.27', '1'], ['2025-05-01', '35.67', '-0.25', '1'], ['2025-05-02', '35.67', '-0.23', '1'], ['2025-05-03', '35.64', '-0.23', '1'], ['2025-05-04', '35.63', '-0.24', '1'], ['2025-05-05', '35.62', '-0.19', '1'], ['2025-06-03', '35.41', '0.23', '1'], ['2025-06-04', '35.49', '0.17', '1'], ['2025-06-05', '35.58', '0.19', '1'], ['2025-06-06', '35.69', '-0.14', '1'], ['2025-06-07', '35.66', '-0.31', '1'], ['2025-06-08', '35.59', '0.02', '1'], ['2025-06-09', '35.60', '0.03', '1'], ['2025-06-10', '35.60', '-0.18', '1'], ['2025-06-11', '35.60', '-0.12', '1'], ['2025-06-13', '35.61', '0.16', '1'], ['2025-06-14', '35.62', '-0.07', '1'], ['2025-06-15', '35.62', '-0.24', '1'], ['2025-06-16', '35.60', '-0.15', '1'], ['2025-06-17', '35.58', '-0.01', '1'], ['2025-06-18', '35.58', '-0.08', '1'], ['2025-06-19', '35.58', '-0.06', '1'], ['2025-06-20', '35.57', '-0.02', '1'], ['2025-06-21', '35.57', '-0.08', '1'], ['2025-06-22', '35.57', '0.08', '1'], ['2025-06-23', '35.57', '-0.10', '1'], ['2025-06-24', '35.57', '0.10', '1'], ['2025-06-25', '35.57', '0.19', '1'], ['2025-06-26', '35.58', '0.01', '1'], ['2025-06-27', '35.58', '0.10', '1'], ['2025-06-28', '35.59', '-0.07', '1'], ['2025-06-29', '35.58', '-0.10', '1'], ['2025-06-30', '35.58', '-0.13', '1'], ['2025-07-01', '35.57', '-0.34', '1'], ['2025-07-02', '35.56', '-0.08', '1'], ['2025-07-03', '35.56', '-0.10', '1'], ['2025-07-04', '35.56', '-0.08', '1'], ['2025-07-05', '35.55', '0.21', '1'], ['2025-07-06', '35.55', '0.06', '1'], ['2025-07-07', '35.55', '0.07', '1'], ['2025-07-08', '35.55', '-0.21', '1'], ['2025-07-09', '35.55', '0.33', '1'], ['2025-07-15', '35.54', '1.02', '1'], ['2025-07-16', '35.58', '0.99', '1'], ['2025-07-17', '35.63', '0.97', '1'], ['2025-07-18', '35.67', '0.78', '1'], ['2025-07-29', '35.67', '0.78', '2'], ['2025-07-30', '35.80', '-0.80', '1'], ['2025-07-31', '35.77', '-0.79', '1'], ['2025-08-01', '35.73', '-0.78', '1'], ['2025-08-02', '35.72', '-8.37', '1'], ['2025-08-03', '35.73', '-0.89', '1'], ['2025-08-04', '35.69', '-0.63', '1'], ['2025-08-05', '35.66', '-0.67', '1'], ['2025-08-06', '35.66', '0.00', '1'], ['2025-08-08', '35.66', '-0.47', '1'], ['2025-08-09', '35.64', '-0.01', '1'], ['2025-08-10', '35.62', '-0.13', '1'], ['2025-08-11', '35.61', '0.04', '1'], ['2025-08-12', '35.62', '0.01', '1'], ['2025-08-13', '35.62', '0.06', '1'], ['2025-08-14', '35.62', '0.28', '1'], ['2025-08-15', '35.64', '-0.26', '1'], ['2025-08-16', '35.57', '-0.54', '1'], ['2025-08-17', '35.48', '0.00', '1']], 'menstrual_dates': [{'mens_date': '2025-08-17', 'period_len': 4}, {'mens_date': '2025-07-21', 'period_len': 6}, {'mens_date': '2025-06-29', 'period_len': 3}, {'mens_date': '2025-06-11', 'period_len': 3}, {'mens_date': '2025-05-24', 'period_len': 3}, {'mens_date': '2025-01-18', 'period_len': 5}]}
    temp_output= gen_temperature_monthly_reports(temp_input)
    print('temp输出',temp_output)

    """
    data_pred = pd.read_csv(
        r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\数据\测试周期报\period_prediction_18(2).csv',
        encoding='utf-8')

    data_click = pd.read_csv(
        r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\数据\测试周期报\period_record_18(2).csv',encoding='utf-8')

    data_questionnaire = pd.read_csv(
        r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\数据\测试周期报\questionnaire_18(2).csv',encoding='utf-8')
    temp_data = pd.read_csv(r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\数据\测试周期报\sleep_feature_18(2).csv')
    user_name = pd.read_csv(r'D:\LLM\month_woman_report\mens_report.csv')

    # data_pred = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批数据\rc_period_prediction_5.20~6.20.csv',
    #     encoding='utf-8')
    #
    # data_click = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批数据\rc_period_record_5.20~6.20_去除体温不符合要求.csv',encoding='utf-8')
    #
    # data_questionnaire = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批数据\quesitionnaire_5.20~6.20.csv',encoding='utf-8')
    # temp_data1 = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批数据\rc_sleep_feature_5.20~6.20.csv',low_memory=False)
    # temp_data2 = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批数据\rc_sleep_feature_6.21~7.20.csv',low_memory=False)
    # temp_data3 = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批数据\rc_sleep_feature_7.21~8.20.csv',low_memory=False)
    # temp_data4 = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批数据\rc_sleep_feature_8.21~9.23.csv')
    #
    # temp_data = pd.concat([temp_data1, temp_data2, temp_data3, temp_data4], axis=0, ignore_index=True)
    #
    #
    #
    # regular_info = pd.read_csv(
    #     r'D:\研发部-算法\生理期\生理期-hq\menstrual_interactive\女性健康3.0\验证线上运行结果与当前修改的区别0918\测试海外的数据\第三批的规律性最终名单.csv',
    #     encoding='ANSI')
    #
    # # common_user_ids = regular_info['用户id'].drop_duplicates().dropna()
    # common_user_ids = [29917]
    common_user_ids = list(set(data_pred['user_id']) & set(data_click['user_id']) & set(data_questionnaire['user_id']))
    predict = pd.DataFrame()
    test_report = pd.DataFrame()
    i = 0
    mens_dates_csv = pd.DataFrame()
    pain_dates_csv = pd.DataFrame()
    temp_dates_csv = pd.DataFrame()
    hrv_dates_csv = pd.DataFrame()
    # common_user_ids = [238874]
    # common_user_ids =user_name['user_id'].tolist()
    for id in common_user_ids:
        i += 1
        print('用户id',id , i)
        user_click = data_click[data_click['user_id'] == id]
        period = user_click[(user_click['is_period'] == 1) & (user_click['is_start'] == 1) & (
                    user_click['period_type'] != 3)].drop_duplicates()  # 用户点击记录中两者同时满足代表该用户是月经的第一天
        period_main_page = period[period['period_type'] == 1]  # 区分经期类型

        questionnaire = \
        data_questionnaire[(data_questionnaire['user_id'] == id) & (data_questionnaire['business_code'] == 'PERIOD')][
            'question_content']
        questionnaire.reset_index(drop=True, inplace=True)

        questionnaire_dict = ast.literal_eval(questionnaire.loc[0])

        user_cycle = questionnaire_dict['periodCycleAvg']
        user_regular = questionnaire_dict['periodSituation']
        predict_length = questionnaire_dict['periodDurationDays']
        user_birthday = questionnaire_dict['birthday'] if 'birthday' in questionnaire_dict else '2000-01-01'
        birthday = datetime.strptime(user_birthday, "%Y-%m-%d")
        today = datetime.today()
        user_age = today.year - birthday.year - ((today.month, today.day) < (birthday.month, birthday.day))

        user_click_mens_dates_utc = pd.to_datetime(period['period_utc'], unit='s')  # 转成时间格式
        user_click_mens_dates = sorted(user_click_mens_dates_utc, reverse=True)  # 用户点击的金标，真实日
        menstrual_cycle = [int((user_click_mens_dates[i] - user_click_mens_dates[i + 1]).days) for i in
                           range(len(user_click_mens_dates) - 1)]
        menstrual_cycle.append(user_cycle)

        # 需判断用户体温数据是否有更新

        # message_info = temp_data[temp_data['user_id'] == id]

        real_date_strp = [date for date in user_click_mens_dates]
        real_date = [date.strftime('%Y-%m-%d') for date in real_date_strp]
        menstrual_cycle = menstrual_cycle[:len(real_date)]
        mens_info_tmp = pd.DataFrame({'用户id': id, '问卷金标': real_date, '月经周期': menstrual_cycle})

        version = 3.6
        note_ques = 0  # note_ques 为1代表用户在问卷阶段,是后台返回的标识符
        note = 0 if not period_main_page.empty and note_ques == 0 else 1  # note 为模拟的标识符；如果想要模拟进入页面之后的情景，需要满足用户点击过主页面的内容，否则按首次进入页面处理
        user_type, message_date = regular_classification(id, mens_info_tmp)

        # main_click_dates = message_info['问卷金标']  # 线上模拟，不对比最后一次预测
        # print('message_date' , type(message_date), message_date)
        mens_cycle_len_6 = []
        mens_period_len_6 = []
        menstrual_dates = []
        for i, row in message_date[:7].iterrows():
            # print(i , row, type(row))
            # print(row['问卷金标'])
            click_tmp = {'mens_date': row['问卷金标'].replace("/", "-"),
                         'period_len': random.randint(1, 7)}

            mens_cycle = row['月经周期']
            period_len = click_tmp['period_len']

            if i < 6:
                mens_cycle_len_6.append(mens_cycle)
                mens_period_len_6.append(period_len)
            menstrual_dates.append(click_tmp)
        mens_blood_len_6 = generate_random_values('blood')
        group_to_output_key = {
            '周期长度': 'cycle_anlzr',
            '周期长度差异': 'cycle_diff_anlzr',
            '经期天数': 'period_anlzr',
            '月经量': 'blood_anlzr',
            '皮肤温度': 'temp_anlzr',
            '痛经': 'pain_anlzr',
            '其他症状': 'symptoms_anlzr',
            'hrv与心情': 'hrv_mood_anlzr'

        }

        # 周期
        cycles_input = {'user_id': id,
                        'mens_cycle_len_6': mens_cycle_len_6,
                        'mens_period_len_6': mens_period_len_6,
                        'mens_blood_len_6': mens_blood_len_6,
                        'user_age': user_age
        }

        mens_report = pd.DataFrame()
        pain_report = pd.DataFrame()
        
        # # # 痛经与症状
        user_pain_records = generate_random_values('pain')
        user_pain_total_cycles = generate_random_values('pain_total', 3)
        user_symptom_records = generate_user_symptom_records()
        pain_and_symptom_input = {'user_id': id,
                                  'user_pain_records': user_pain_records,
                                  'user_pain_total_cycles':user_pain_total_cycles,
                                  'user_symptom_records':user_symptom_records
                                  }
        print('========================周期统计输入===========================')
        print('cycles_input:', cycles_input)
        print('cycles_output:', gen_menstrual_cycles_monthly_report(cycles_input))
        cycles_output, texts_cycle ,_= gen_menstrual_cycles_monthly_report(cycles_input)

        print('cycles_output:',cycles_output)
        print('文案', texts_cycle)
        print('==========================================================')

        print('========================痛经与症状输入===========================')
        print('pain_and_symptom_input:', pain_and_symptom_input)
        pain_and_symptom_output, texts_pain,_ = gen_pain_symptoms_monthly_report(pain_and_symptom_input)
        print('pain_and_symptom_out:',pain_and_symptom_output)
        print('文案', texts_pain )
        print('==========================================================')

        mens_report.loc[i, 'user_id'] = id
        mens_report.loc[i, 'cycles_len'] = len(cycles_input['mens_cycle_len_6'])
        mens_report.loc[i, 'input'] = str(cycles_input)
        mens_report.loc[i, 'output'] = str(cycles_output)
        for idx, text in enumerate(texts_cycle, start=1):  # 从1开始计数，对应text1、text2...
            col_name = f"text{idx}"  # 生成列名：text1、text2、text3...
            mens_report.loc[i, col_name] = text
        # print('输出', output)
        mens_dates_csv = pd.concat([mens_dates_csv, mens_report])

        pain_report.loc[i, 'user_id'] = id

        pain_report.loc[i, 'input'] = str(pain_and_symptom_input)
        pain_report.loc[i, 'output'] = str(pain_and_symptom_output)
        for idx, text in enumerate(texts_pain, start=1):  # 从1开始计数，对应text1、text2...
            col_name = f"text{idx}"  # 生成列名：text1、text2、text3...
            pain_report.loc[i, col_name] = text
        # print('输出', output)
        pain_dates_csv = pd.concat([pain_dates_csv, pain_report])

    
         #==========================================体温与心率取值=========================================================
        if len(message_date) >= 6:
            start_date = message_date.iloc[5]['问卷金标']
        else:
            start_date = message_date.iloc[-1]['问卷金标']
        start_date = pd.to_datetime(start_date)
        end_date = pd.to_datetime(message_date.iloc[0]['问卷金标'])
        print('开始和结束日',message_date, start_date , end_date)
        temp_data['date_sleep'] = pd.to_datetime(temp_data['date_sleep'])
        user_data = temp_data[(temp_data['user_id'] == id ) & (temp_data['flag'] != -1) & (temp_data['date_sleep'] >= start_date) & (temp_data['date_sleep'] <= end_date) ].copy()  # 用户睡眠表内的内容

        user_data = user_data[:360]
        user_data['date_sleep'] = user_data['date_sleep'].dt.strftime('%Y-%m-%d')
        # print(type(user_data.iloc[0]['flag']))

        # =============================================================================================================

        # 体温
        temp_data_new = user_data[['date_sleep', 'temp_benchmark', 'temp_offset', 'flag']]
        print('体温的长度',len(temp_data_new))
        if len(temp_data_new) > 30:

            temp_data_array = temp_data_new.values.tolist()
            temp_data_array_str = [[str(value) for value in row] for row in temp_data_array]

            # temp_data_tuple = [tuple(str(row)) for row in temp_data_new.to_records(index=False)]
            # user_temp_new = json.dumps(temp_data_tuple, default=default_to_native)
            temp_input = {'user_id': id,
                          'temp_data':temp_data_array_str,
                          'menstrual_dates':menstrual_dates

            }
            print('========================体温统计输入===========================')
            print('hrv_input:', temp_input)

            temp_output, temp_message = gen_temperature_monthly_reports(temp_input)
            temp_dates_csv = pd.concat([temp_dates_csv, temp_message])
            print('==========================================================')
            print('temp_output:', temp_output)


        # hrv
        hrv_data_new = user_data[['date_sleep', 'hr_avg', 'hrv_avg', 'flag']]
        if len(hrv_data_new) > 30:

            hrv_data_array = hrv_data_new.values.tolist()
            hrv_data_array_str = [[str(value) for value in row] for row in hrv_data_array]

            mood_records = generate_unique_mood_records_desc(start_date, end_date,  180)
            # print('输入月经日期', menstrual_dates,)
            hrv_input = {'user_id': id,
                          'hrv_data': hrv_data_array_str,
                          'menstrual_dates': menstrual_dates,
                          'mood_records':mood_records

                          }
            print('========================hrv统计输入===========================')
            print('hrv_input:', hrv_input)

            hrv_output , hrv_message,_ = gen_hrv_mood_monthly_reports(hrv_input)
            hrv_dates_csv = pd.concat([hrv_dates_csv, hrv_message])
            print('hrv_output:', hrv_output)



    # mens_dates_csv.to_csv(r'D:\LLM\month_woman_report\mens_report_re918.csv', index = False)
    # pain_dates_csv.to_csv(r'D:\LLM\month_woman_report\pain_report_re918.csv', index = False)
    # temp_dates_csv.to_csv(r'D:\LLM\month_woman_report\temp_report_re918.csv', index = False)
    # hrv_dates_csv.to_csv(r'D:\LLM\month_woman_report\hrv_report_re918.csv', index = False)


    mens_dates_csv.to_csv(r'D:\LLM\uerportrait\women\自测报告\mens_report_re918.csv', index = False)
    pain_dates_csv.to_csv(r'D:\LLM\uerportrait\women\自测报告\pain_report_re918.csv', index = False)
    temp_dates_csv.to_csv(r'D:\LLM\uerportrait\women\自测报告\temp_report_re918.csv', index = False)
    hrv_dates_csv.to_csv(r'D:\LLM\uerportrait\women\自测报告\hrv_report_re918.csv', index = False)